/**
 *  @file  SocketHandle.h version 1.0 2007-11-20
 *  @brief Define wrapper class SocketHandle for socket.
 *  Copyright (c) 2007 by @author Zhao Jun <abitfree@gmail.com>
 */

#ifndef __SOCKET_HANDLE_H__
#define __SOCKET_HANDLE_H__

#include "NetCommon.h"


namespace vs {
namespace net {

/**
@brief Base class for TCP/UDP stream.
This class encapsulates the underlying socket.
*/
class SocketHandle 
{
public:
	/// Explicit constructor.
	explicit SocketHandle(SOCKET_HANDLE handle = INVALID_SOCKET_HANDLE);
	
	/// Destructor.
	~SocketHandle();
	
	/// Create a socket.
	bool Create(int domain = AF_INET, int type = SOCK_STREAM, int protocol = 0);
	
	/// Attach a socket handle.
	bool Attach(SOCKET_HANDLE handle = INVALID_SOCKET_HANDLE);
	
	/// Detach a socket handle, and become invalid state.
	SOCKET_HANDLE Detach();
	
	/// Get the underlying socket handle.
	SOCKET_HANDLE GetHandle() const;
	
	/// Get the state of the socket handle.
	bool IsValid() const;
	
	/// Convert to the underlying socket handle.
	operator SOCKET_HANDLE() const;
	
	/// Close socket handle.
	void Close();

	/// Helper function, convert an blocking socket to non-blocking socket.
	static bool ToNonblocking(SOCKET_HANDLE handle);

	/// Helper function, convert an non-blocking socket to blocking socket.
	static bool ToBlocking(SOCKET_HANDLE handle);

private:
	// The underlying socket handle.
	SOCKET_HANDLE handle_;
};

INLINE
SocketHandle::SocketHandle(SOCKET_HANDLE handle)
{
	Attach(handle);
}

INLINE
SocketHandle::~SocketHandle()
{
	if (handle_ != INVALID_SOCKET_HANDLE)
	{
		Close();
	}
}

INLINE
bool SocketHandle::Create(int domain, int type, int protocol)
{
	if (handle_ != INVALID_SOCKET_HANDLE)
	{
		Close();
	}
	
	handle_ = socket(domain, type, protocol);
	return handle_ != SOCKET_ERROR;
}

INLINE
bool SocketHandle::Attach(SOCKET_HANDLE handle)
{
	handle_ = handle;
	return (handle_ != INVALID_SOCKET_HANDLE);
}

INLINE
SOCKET_HANDLE SocketHandle::Detach()
{
	SOCKET_HANDLE handle = handle_;
	handle_ = INVALID_SOCKET_HANDLE;
	return handle;
}

INLINE
SOCKET_HANDLE SocketHandle::GetHandle() const
{
	return handle_;
}

INLINE
bool SocketHandle::IsValid() const
{
	return (handle_ != INVALID_SOCKET_HANDLE);
}

INLINE
SocketHandle::operator SOCKET_HANDLE() const
{
	return GetHandle();
}

INLINE
void SocketHandle::Close()
{
#ifdef WIN32
	closesocket(handle_);
#else
	close(handle_);
#endif
	handle_ = INVALID_SOCKET_HANDLE;
}

INLINE
bool SocketHandle::ToNonblocking(SOCKET_HANDLE handle)
{
#ifdef WIN32
	unsigned long one = 1;
	return (ioctlsocket(handle, FIONBIO, &one) == 0);
#else
	int flags = fcntl(handle, F_GETFL, 0);
	return (fcntl(GetHandle(), F_SETFL, flags|O_NONBLOCK) != -1);
#endif
}

INLINE
bool SocketHandle::ToBlocking(SOCKET_HANDLE handle)
{
#ifdef WIN32
	unsigned long zero = 0;
	return (ioctlsocket(handle, FIONBIO, &zero) == 0);
#else
	int flags = fcntl(handle, F_GETFL, 0);
	return (fcntl(GetHandle(), F_SETFL, flags & ~O_NONBLOCK) != -1);
#endif
}
}	// namespace net
}	// namespace vs

#endif	// __SOCKET_HANDLE_H__
